/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.googlecode.j4sc.conversion;

import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpStatus;

import com.googlecode.j4sc.service.Service;
import com.googlecode.j4sc.service.ServiceException;
import com.googlecode.j4sc.submission.Submission;
import com.googlecode.j4sc.submission.SubmissionReference;

/**
 * The Conversion class is returned as a result of calling the
 * {@link Service#retrieve(SubmissionReference)}. It contains the Status of the
 * conversion and the converted text as well as other attributes of the
 * submission
 * 
 * @author Raj Patel, Dariusz Lorenc
 */
public class Conversion {

    /**
     * The status of the Conversion
     * 
     * @author Raj Patel, Dariusz Lorenc
     */
    public enum Status {

        /**
         * The submission is still being processed, retry the
         * {@link Service#retrieve(SubmissionReference)} after some time
         */
        PENDING,
        /**
         * The audio has been converted successfully.
         */
        CONVERTED,
        /**
         * The audio could not be converted
         */
        UNCONVERTED,
        /**
         * The audio was of poor quality or contained little or no convertible
         * speech
         */
        INAUDIBLE,
        /**
         * The submission couldn't be converted due to system error
         */
        SYSTEM_ERROR,
        /**
         * The submission audio was too long (over 30 seconds)
         */
        LONG;

        private static Status toStatus(String value) {
            return Status.valueOf(convertToEnumName(value));
        }

        private static String convertToEnumName(String value) {
            return value.replace('-', '_').toUpperCase();
        }
    }

    private enum Element {
        STATUS("<status>", "</status>"), TEXT("<text><![CDATA[", "]]></text>"), ACCOUNT_ID("<account-id>",
                "</account-id>"), REFERENCE("<reference>", "</reference>"), APPLICATION_NAME("<app-name>",
                "</app-name>"), SPINVOX_REFERENCE("<spinvox>", "</spinvox>");

        private final String startTag;
        private final String endTag;

        private Element(String startTag, String endTag) {
            this.startTag = startTag;
            this.endTag = endTag;
        }

        private String extractValueFrom(String xml) {
            return StringUtils.substringBetween(xml, this.startTag, this.endTag);
        }
    }

    private Status status;
    private String text;
    private String accountId;
    private String reference;
    private String applicationName;
    private String spinVoxReference;

    /**
     * Construct a new instance
     * 
     * @param statusCode
     *            a status code of HTTP response received from the SpinVox
     *            Create service
     * @param statusDescription
     *            the status description (reason phrase)
     * @param xml
     *            XML content of HTTP response received from the SpinVox Create
     *            service
     * 
     * @throws ServiceException
     */
    public Conversion(int statusCode, String statusDescription, String xml) throws ServiceException {
        switch (statusCode) {
        case HttpStatus.SC_NOT_FOUND:
            this.status = Status.PENDING;
            break;
        case HttpStatus.SC_OK:
            extractElementsFromXml(xml);
            break;
        default:
            throw new ServiceException(statusCode, statusDescription);
        }
    }

    /**
     * The processing status of this Conversion
     * 
     * @return the {@link Status}
     */
    public Status getStatus() {
        return this.status;
    }

    /**
     * Checks whether conversion status is {@link Status#PENDING}.
     * 
     * @return true when status is {@link Status#PENDING} otherwise false
     */
    public boolean isPending() {
        return Status.PENDING.equals(this.status);
    }

    /**
     * The converted text if {@link Status#CONVERTED} or text describing the
     * {@link Status}
     * 
     * @return the converted text
     */
    public String getText() {
        return this.text;
    }

    /**
     * The SpinVox Create Account ID against which the Submission was made
     * 
     * @return the Account ID
     */
    public String getAccountId() {
        return this.accountId;
    }

    /**
     * The reference provided in the {@link Submission} for this
     * {@link Conversion}
     * 
     * @return the reference
     */
    public String getReference() {
        return this.reference;
    }

    /**
     * The application name against which the submission was made
     * 
     * @return the application name
     */
    public String getApplicationName() {
        return this.applicationName;
    }

    /**
     * The internal SpinVox reference for this Conversion
     * 
     * @return the SpinVox reference
     */
    public String getSpinVoxReference() {
        return this.spinVoxReference;
    }

    private void extractElementsFromXml(String xml) {
        this.status = Status.toStatus(Element.STATUS.extractValueFrom(xml));
        this.text = Element.TEXT.extractValueFrom(xml);
        this.accountId = Element.ACCOUNT_ID.extractValueFrom(xml);
        this.reference = Element.REFERENCE.extractValueFrom(xml);
        this.applicationName = Element.APPLICATION_NAME.extractValueFrom(xml);
        this.spinVoxReference = Element.SPINVOX_REFERENCE.extractValueFrom(xml);
    }
}
